import cv2
import numpy as np

# 常用颜色HSV范围
HSV_DICT = {
    'black': [(0, 0, 0), (180, 255, 46)],
    'gray': [(0, 0, 46), (180, 30, 220)],
    'white': [(0, 0, 221), (180, 30, 255)],
    'red': [(0, 43, 46), (10, 255, 255)],
    'red2': [(156, 43, 46), (156, 255, 255)],
    'orange': [(11, 43, 46), (25, 255, 255)],
    'yellow': [(26, 43, 46), (34, 255, 255)],
    'green': [(35, 43, 46), (77, 255, 255)],
    'cyan': [(78, 43, 46), (99, 255, 255)],
    'blue': [(100, 43, 46), (124, 255, 255)],
    'purple': [(125, 43, 46), (155, 255, 255)],
}


def process_image_with_morphology(image, gaussian_blur_ksize=(5, 5), gaussian_blur_sigma=0, erosion_iterations=1,
                                  erosion_ksize=(3, 3), dilation_iterations=1, dilation_ksize=(3, 3)):
    """
       对输入图像进行形态学处理，包括灰度化、高斯模糊、腐蚀和膨胀操作。

       Args:
           image (np.ndarray): 输入的彩色图像，通常为BGR格式。
           gaussian_blur_ksize (tuple, optional): 高斯模糊操作中的核大小。默认为(5, 5)。
           gaussian_blur_sigma (float, optional): 高斯模糊操作中的标准差σ。默认为0。
           erosion_iterations (int, optional): 腐蚀操作的迭代次数。默认为1。
           erosion_ksize (tuple, optional): 腐蚀操作中的核大小。默认为(3, 3)。
           dilation_iterations (int, optional): 膨胀操作的迭代次数。默认为1。
           dilation_ksize (tuple, optional): 膨胀操作中的核大小。默认为(3, 3)。

       Returns:
           np.ndarray: 经过处理后的灰度图像，已经过腐蚀和膨胀操作。
       """
    # 转换为灰度图像
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # 高斯模糊降噪
    blurred = cv2.GaussianBlur(gray, gaussian_blur_ksize, gaussian_blur_sigma)

    # 腐蚀操作
    kernel_erosion = np.ones(erosion_ksize, np.uint8)
    eroded = cv2.erode(blurred, kernel_erosion, iterations=erosion_iterations)

    # 膨胀操作
    kernel_dilation = np.ones(dilation_ksize, np.uint8)
    dilated = cv2.dilate(eroded, kernel_dilation, iterations=dilation_iterations)

    # 如果需要，可以进一步进行开操作（先腐蚀后膨胀）或闭操作（先膨胀后腐蚀）
    # 例如，开操作：
    # opened = cv2.morphologyEx(blurred, cv2.MORPH_OPEN, kernel_erosion)

    # 返回处理后的图像
    return dilated


def laplacian_sharpen(image, kernel_size=3, sigma=1.0, alpha=1.0):
    """
       对输入图像进行拉普拉斯锐化。

       Args:
           image (np.ndarray): 输入的彩色图像，通常为BGR格式。
           kernel_size (int, optional): 拉普拉斯算子的尺寸。通常选择3或5。默认为3。
           sigma (float, optional): 高斯模糊的标准差σ。用于在锐化之前减少噪声。默认为1.0。
           alpha (float, optional): 锐化强度的系数。控制拉普拉斯增强图像在锐化过程中的权重。默认为1.0。

       Returns:
           np.ndarray: 经过拉普拉斯锐化后的图像，与输入图像具有相同的类型和尺寸。

       """
    # 使用高斯模糊减少噪声
    blurred = cv2.GaussianBlur(image, (kernel_size, kernel_size), sigma)

    # 定义拉普拉斯算子
    if kernel_size == 3:
        laplacian = np.array([[0, -1, 0],
                              [-1, 4, -1],
                              [0, -1, 0]], dtype=np.float32)
    elif kernel_size == 5:
        laplacian = np.array([[0, 0, -1, 0, 0],
                              [0, -1, -2, -1, 0],
                              [-1, -2, 16, -2, -1],
                              [0, -1, -2, -1, 0],
                              [0, 0, -1, 0, 0]], dtype=np.float32)
        # 可以根据需要添加其他尺寸的拉普拉斯算子
    else:
        raise ValueError("Unsupported kernel size for Laplacian filter.")

        # 应用拉普拉斯算子
    laplacian_img = cv2.filter2D(blurred, -1, laplacian)

    # 锐化图像 = 原始图像 + 拉普拉斯增强图像
    # 注意：我们可能需要调整拉普拉斯增强图像的权重（alpha）来达到最佳效果
    # alpha控制锐化强度的系数
    sharpened_img = cv2.addWeighted(image, 1.0, laplacian_img, alpha, 0)

    # 确保像素值在0-255范围内
    sharpened_img = np.clip(sharpened_img, 0, 255).astype(np.uint8)

    return sharpened_img


def calculate_roi_color_average(img, x, y, w, h):
    """
        计算给定图像中感兴趣区域(ROI)的颜色平均值。

        Args:
            img (numpy.ndarray): 输入的图像，应为BGR格式的numpy数组。
            x (int): ROI左上角在x轴上的坐标。
            y (int): ROI左上角在y轴上的坐标。
            w (int): ROI的宽度。
            h (int): ROI的高度。

        Returns:
            tuple or None: 包含三个整数值的元组，分别代表蓝色、绿色和红色通道的平均值。
                如果ROI为空（即x, y, w, h的值没有形成一个有效的ROI），则返回None。

        """
    roi = img[y:y + h, x:x + w]

    # 确保ROI不是空的
    if roi.size == 0:
        return None  # 或者你可以返回一个默认值，如(0, 0, 0)

    # 计算每个颜色通道的平均值
    b, g, r = cv2.split(roi)
    avg_b = int(np.mean(b))
    avg_g = int(np.mean(g))
    avg_r = int(np.mean(r))

    # 返回颜色平均值
    return avg_b, avg_g, avg_r


def calculate_average_color(contour, color_image):
    """
        计算给定轮廓在彩色图像中的内部区域的平均颜色。

        Args:
            contour (list[numpy.ndarray]): 轮廓的坐标点列表，通常是一个NumPy数组，
                其形状为(n, 1, 2)，其中n是轮廓点的数量，每个点表示为(x, y)坐标。
            color_image (numpy.ndarray): 输入的彩色图像，应为BGR格式的NumPy数组。

        Returns:
            tuple or None: 包含三个浮点数值的元组，分别代表蓝色、绿色和红色通道的平均值。
                如果轮廓内部没有像素，则返回None。

    """
    # 创建一个与原始图像大小相同的全零矩阵（掩码），但数据类型为uint8
    mask = np.zeros(color_image.shape[:2], dtype=np.uint8)

    # 使用fillPoly填充轮廓内部，这里使用白色（255）填充
    cv2.fillPoly(mask, [contour], (255))

    # 使用掩码来获取轮廓内部的像素
    roi_pixels = color_image[mask == 255]

    # 如果roi_pixels非空，计算（b，g，r）的平均值
    if roi_pixels.size > 0:
        avg_color = np.mean(roi_pixels, axis=0)
        # 返回一个包含B、G、R三种颜色平均值的元组
        return tuple(avg_color)
    else:
        print("No pixels found inside the contour.")
        return None


if __name__ == '__main__':

    # 使用示例
    image = cv2.imread('images/face_detection/1.jpg')
    processed_image = process_image_with_morphology(image, gaussian_blur_ksize=(5, 5), erosion_iterations=2,
                                                    dilation_iterations=2)
    sharpened_image = laplacian_sharpen(image, kernel_size=3, sigma=1.0)
    cv2.imshow('Sharpened Image', sharpened_image)
    # 显示原始图像和处理后的图像
    cv2.imshow('Original Image', image)
    cv2.imshow('Processed Image', processed_image)

    cv2.waitKey(0)
    cv2.destroyAllWindows()